﻿//// http://mulps.wordpress.com/2009/05/01/in-memory-compression-by-lzma-in-c/


    //var buffer =
        //    Encoding.Default.GetBytes("Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here Your string here");
        //var mmmmSource = new MemoryStream(buffer);
        //var zz = new SevenZip.Compression.LZMA.LZMACoder();
        //var mmmmDest = zz.compress(mmmmSource);
        //Debug.Log("GZipStream original:" + mmmmSource.Length + " dest:" + mmmmDest.Length);

namespace SevenZip.Compression.LZMA
{
    using System;
    using System.IO;

    public class LZMACoder : IDisposable
    {
        private bool isDisposed = false;

        //These properties are straight copy from the SDK.
        //Actually, I don't know what these mean.

        private static Int32 dictionary = 1 << 21; //No dictionary
        private static Int32 posStateBits = 2;
        private static Int32 litContextBits = 3;   // for normal files  // UInt32 litContextBits = 0; // for 32-bit data
        private static Int32 litPosBits = 0;       // UInt32 litPosBits = 2; // for 32-bit data
        private static Int32 algorithm = 2;
        private static Int32 numFastBytes = 128;
        private static bool eos = false;
        private static string mf = "bt4";

        private static CoderPropID[] propIDs =
        {
            CoderPropID.DictionarySize,
            CoderPropID.PosStateBits,
            CoderPropID.LitContextBits,
            CoderPropID.LitPosBits,
            CoderPropID.Algorithm,
            CoderPropID.NumFastBytes,
            CoderPropID.MatchFinder,
            CoderPropID.EndMarker
        };
        private static object[] properties =
        {
            dictionary,
            posStateBits,
            litContextBits,
            litPosBits,
            algorithm,
            numFastBytes,
            mf,
            eos
        };

        public LZMACoder()
        {
            if (BitConverter.IsLittleEndian == false)
            {
                this.Dispose();
                throw new Exception("Not implemented");
            }
        }

        public MemoryStream decompress(MemoryStream inStream)
        {
            return decompress(inStream, false);
        }

        public MemoryStream decompress(MemoryStream inStream, bool closeInStream)
        {
            inStream.Position = 0;
            var outStream = new MemoryStream();

            var properties = new byte[5];
            if (inStream.Read(properties, 0, 5) != 5)
            {
                throw new Exception("input .lzma is too short");
            }

            var decoder = new LZMA.Decoder();
            decoder.SetDecoderProperties(properties);

            long outSize = 0;

            if (BitConverter.IsLittleEndian)
            {
                for (var i = 0; i < 8; i++)
                {
                    var v = inStream.ReadByte();
                    if (v < 0)
                    {
                        throw new Exception("Can't Read 1");
                    }

                    outSize |= ((long)(byte)v) << (8 * i);
                }
            }

            var compressedSize = inStream.Length - inStream.Position;
            decoder.Code(inStream, outStream, compressedSize, outSize, null);

            if (closeInStream)
            {
                inStream.Close();
            }

            return outStream;
        }

        public MemoryStream compress(MemoryStream inStream)
        {
            return this.compress(inStream, false);
        }

        public MemoryStream compress(MemoryStream inStream, bool closeInStream)
        {
            inStream.Position = 0;
            var fileSize = inStream.Length;
            var outStream = new MemoryStream();

            var encoder = new LZMA.Encoder();
            encoder.SetCoderProperties(propIDs, properties);
            encoder.WriteCoderProperties(outStream);

            if (BitConverter.IsLittleEndian)
            {
                var lengthHeader = BitConverter.GetBytes(fileSize);
                outStream.Write(lengthHeader, 0, lengthHeader.Length);
            }

            encoder.Code(inStream, outStream, -1, -1, null);

            if (closeInStream)
            {
                inStream.Close();
            }

            return outStream;
        }

        ~LZMACoder()
        {
            this.Dispose();
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (this.isDisposed == false)
            {
                if (disposing)
                {
                    //Console.WriteLine("dispose");
                    GC.SuppressFinalize(this);
                }
            }

            this.isDisposed = true;
        }
    }
}